[Enhancement]Keep CallKit answer actions alive during WebRTC audio setup#1081
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughAdds a CallKit completion hook to the join flow: CallKit answer actions now receive an ActionCompletion that is invoked after WebRTC configures the audio device module, enabling explicit handoff of audio session ownership before continuing the join flow. Changes
Sequence DiagramsequenceDiagram
participant CallKit as CallKit System
participant Service as CallKitService
participant Adapter as WebRTCStateAdapter
participant Audio as Audio Device Module
CallKit->>Service: Answer call action
Service->>Service: Create ActionCompletion (action.fulfill)
Service->>Service: Set joinSource = .callKit(ActionCompletion)
Service->>Adapter: Start join / configure audio
Adapter->>Audio: Configure audio device module
Audio-->>Adapter: Configuration complete
Adapter->>Service: Invoke ActionCompletion.complete()
Service->>CallKit: Fulfill answer action
CallKit->>CallKit: Release audio session
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Public Interface🚀 No changes affecting the public interface. |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
Sources/StreamVideo/CallKit/CallKitService.swift (1)
479-491:⚠️ Potential issue | 🟠 MajorComplete the
CXAnswerCallActionexactly once.The callback introduced in the
joinSourceassignment already completes the answer action during audio session configuration. Line 486 still callsaction.fulfill(), and line 491 can still callaction.fail()after that callback has run. Ifjoin()completes after the audio-session handoff, the same action gets completed twice, violating CallKit's API contract. Remove the unconditional post-joinaction.fulfill()and guard the failure path so it only completes the action if the callback has not already done so.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Sources/StreamVideo/CallKit/CallKitService.swift` around lines 479 - 491, The answer action is being completed twice: once inside the joinSource callback and again unconditionally after try await callToJoinEntry.call.join and in the catch block; remove the unconditional action.fulfill() after the join and guard the failure path so action.fail() is only called if the callback didn't already complete the action. Implement this by introducing a local Bool (e.g., didCompleteAnswerAction = false) captured by the joinSource closure which sets didCompleteAnswerAction = true when it calls action.fulfill(), then after try await callToJoinEntry.call.join omit action.fulfill(), and in the catch block call action.fail() only if didCompleteAnswerAction is false (also ensure you still call callToJoinEntry.call.leave(), set(nil, for: action.callUUID), and log.error(...) as before).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@CHANGELOG.md`:
- Line 17: The changelog entry "Ensure CallKit joins keep the answer action
completion alive until WebRTC has configured the audio device module." has a
mismatched PR reference: it is labeled `#1081` but the hyperlink points to
pull/1080; update the hyperlink target in CHANGELOG.md so the URL uses pull/1081
to match the label (or alternatively change the label to `#1080` if the intended
PR is 1080), ensuring the label and link are consistent.
---
Outside diff comments:
In `@Sources/StreamVideo/CallKit/CallKitService.swift`:
- Around line 479-491: The answer action is being completed twice: once inside
the joinSource callback and again unconditionally after try await
callToJoinEntry.call.join and in the catch block; remove the unconditional
action.fulfill() after the join and guard the failure path so action.fail() is
only called if the callback didn't already complete the action. Implement this
by introducing a local Bool (e.g., didCompleteAnswerAction = false) captured by
the joinSource closure which sets didCompleteAnswerAction = true when it calls
action.fulfill(), then after try await callToJoinEntry.call.join omit
action.fulfill(), and in the catch block call action.fail() only if
didCompleteAnswerAction is false (also ensure you still call
callToJoinEntry.call.leave(), set(nil, for: action.callUUID), and log.error(...)
as before).
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 31eba2dd-2dce-4c4c-aefd-52a55e8bd07f
📒 Files selected for processing (8)
CHANGELOG.mdSources/StreamVideo/CallKit/CallKitService.swiftSources/StreamVideo/Models/JoinSource.swiftSources/StreamVideo/WebRTC/v2/WebRTCStateAdapter.swiftStreamVideoTests/Call/Call_Tests.swiftStreamVideoTests/Controllers/CallController_Tests.swiftStreamVideoTests/WebRTC/v2/WebRTCCoorindator_Tests.swiftStreamVideoTests/WebRTC/v2/WebRTCStateAdapter_Tests.swift
SDK Size
|
StreamVideo XCSize
Show 8 more objects
|
|



🔗 Issue Links
Resolves https://linear.app/stream/issue/IOS-1477/improve-callkit-connectingjoining-state-by-moving-action-fulfilment
🎯 Goal
Ensure CallKit answer actions remain alive until WebRTC has configured the
audio device module, while documenting and covering the new join-source flow.
📝 Summary
JoinSourceWebRTCStateAdapterafter the audio devicemodule is configured
🛠 Implementation
CallKitServicenow stores a.callKit(.init { ... })join source so theanswer action completion can travel with the join request.
JoinSourcedocuments that payload and compares CallKit sources by a stable identifier so
tests and state comparisons can still work predictably.
WebRTCStateAdapter.configureAudioSession(source:)detects the CallKit payloadand completes it immediately after
setAudioDeviceModule(...)succeeds. Theaffected tests were updated to compare against a concrete
JoinSource.callKitvalue, and a dedicated adapter test now covers the completion callback path.
🎨 Showcase
N/A
🧪 Manual Testing Notes
call joins.
☑️ Contributor Checklist
Summary by CodeRabbit
Bug Fixes
Tests
Documentation